package zack.project.domain.strategy.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import zack.project.domain.strategy.adapter.repository.IStrategyRepository;
import zack.project.domain.strategy.model.entity.RaffleAwardEntity;
import zack.project.domain.strategy.model.entity.RaffleFactorEntity;
import zack.project.domain.strategy.model.entity.StrategyAwardEntity;
import zack.project.domain.strategy.service.armory.IStrategyDispatch;
import zack.project.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import zack.project.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import zack.project.types.enums.ResponseCode;
import zack.project.types.exception.AppException;

import java.util.Date;

/**
 * 抽象抽奖策略实现类,定义抽奖流程
 *
 * @author A1793
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {

    // 策略仓储服务 -> domain层像一个大厨，仓储层提供米面粮油
    protected IStrategyRepository repository;
    // 策略调度服务 -> 只负责抽奖处理，通过新增接口的方式，隔离职责，不需要使用方关心或者调用抽奖的初始化
    protected IStrategyDispatch strategyDispatch;

    protected DefaultChainFactory logicChainFactory;

    protected DefaultTreeFactory logicTreeFactory;

    public AbstractRaffleStrategy(DefaultChainFactory logicChainFactory,
                                  DefaultTreeFactory logicTreeFactory,
                                  IStrategyRepository repository,
                                  IStrategyDispatch strategyDispatch) {
        this.logicChainFactory = logicChainFactory;
        this.logicTreeFactory = logicTreeFactory;
        this.repository = repository;
        this.strategyDispatch = strategyDispatch;
    }

    @Override
    public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {

        Long strategyId = raffleFactorEntity.getStrategyId();
        String userId = raffleFactorEntity.getUserId();
        // 1. 参数校验
        if (strategyId == null || StringUtils.isBlank(userId)) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        log.info("抽奖策略计算 userId:{} strategyId:{}", userId, strategyId);

        // 2. 抽奖前 - 规则过滤
        DefaultChainFactory.StrategyAwardVO chianStrategyAwardVO =
                raffleLogicChain(userId, strategyId);
        log.info("抽奖策略计算-责任链 {} {} {} {}", userId, strategyId, chianStrategyAwardVO.getAwardId(), chianStrategyAwardVO.getLogicModel());
        //如果不是责任链的默认节点随机抽奖产生的奖品(是由黑名单或权重规则产生),则直接返回奖品
        if (!DefaultChainFactory.LogicModel.RULE_DEFAULT.getCode()
                .equals(chianStrategyAwardVO.getLogicModel())) {
            return buildRaffleAwardEntity(strategyId,
                    chianStrategyAwardVO.getAwardId(),
                    chianStrategyAwardVO.getAwardRuleValue());
        }
        //对随机抽奖获得的奖品进行规则树检验,判断该用户是否满足获得条件(判据:已抽奖次数,该奖品库存)
        DefaultTreeFactory.StrategyAwardVO treeStrategyAwardVO = raffleLogicTree(userId,
                strategyId,
                chianStrategyAwardVO.getAwardId(),
                raffleFactorEntity.getEndTime());
        log.info("抽奖策略计算-规则树 {} {} {} {}",
                userId,
                strategyId,
                treeStrategyAwardVO.getAwardId(),
                treeStrategyAwardVO.getAwardRuleValue());


        return buildRaffleAwardEntity(strategyId, treeStrategyAwardVO.getAwardId(),
                treeStrategyAwardVO.getAwardRuleValue());

    }

    private RaffleAwardEntity buildRaffleAwardEntity(Long strategyId, Integer awardId, String awardConfig) {
        StrategyAwardEntity strategyAwardEntity = repository.queryStrategyEntity(strategyId, awardId);
        return RaffleAwardEntity.builder()
                .awardId(awardId)
                .awardConfig(awardConfig)
                .awardTitle(strategyAwardEntity.getAwardTitle())
                .sort(strategyAwardEntity.getSort())
                .ruleModels(strategyAwardEntity.getRuleModels())
                .build();
    }

    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId);

    public abstract DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId);

    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId, Date endDateTime);
}


